package com.thinkit.bigdata.core.util.audios;

/**
 * 生成44个字节的标准8K8bit语音头信息
 * 文件注释中的 # 代表字节
 * Created by BanAiqin on 2016/12/2.
 */

import java.io.ByteArrayOutputStream;
import java.io.IOException;

public class WaveHeader8K8bitPcm {

    public short channels = 1;//22-23#	声道数: 1 Mono; 2 Stereo
    public short sampleRate = 8000;//24-27# 采样率(每秒的样本采集次数): 8K , 16K , 44.1K
    public short bitsPerSample = 8;//34-35# 采样精度: 一次采样包含的bit位个数
    //    RIFF头,前12个字节
    private char fileID[] = {'R', 'I', 'F', 'F'};//0-3# 以 大端模式 存储内容为"RIFF"的ASCII码(0x52494646)
    private int fileLength;//4-7# 存储整个文件的字节数(不包含 fileID 和 fileLength 这8个字节)
    private char wavTag[] = {'W', 'A', 'V', 'E'};//8-11# 以 大端模式 存储内容为"WAVE"的ASCII码(0x57415645)
    //    RIFF体,包含fmt子块和data字块
    //    fmt子块
    private char fmtHdrID[] = {'f', 'm', 't', ' '};//12-15#以 大端模式 存储内容为"fmt "的ASCII码(0x666d7420)
    private int fmtHdrLeth = 16;//16-19# 存储子块"fmt "的字节数(不包含 fmtHdrID 和 fmtHdrLeth 这8个字节)
    private short formatTag = 1;//20-21#	编码格式: 1 PCM ; 6 Alaw; 7 Ulaw
    private short blockAlign = (short) (channels * bitsPerSample / 8);//32-33# 字节对齐最小单位,即每次采样大小=采样精度×声道数÷8 (单位是 字节 )
    private int avgBytesPerSec = blockAlign * sampleRate;//28-31# 数据传输速率: 采样率×每次采样大小 (单位是 字节 )
    private char dataHdrID[] = {'d', 'a', 't', 'a'};//36-39# 以 大端模式 存储内容为"data"的ASCII码(0x64617461)
    private int dataHdrLeth;//40-43# 存储子块"data"的字节数(不包含Subchunk2ID和Subchunk2Size这8个字节)

    public WaveHeader8K8bitPcm(int fileLength, short formatTag, short bitsPerSample) {
        this.fileLength = fileLength + (44 - 8);
        dataHdrLeth = fileLength;
        this.formatTag = formatTag;
        this.bitsPerSample = bitsPerSample;
    }

    public WaveHeader8K8bitPcm(int fileLength) {
        this.fileLength = fileLength + (44 - 8);
        dataHdrLeth = fileLength;
    }

    public WaveHeader8K8bitPcm(int fileLength, short channels, short sampleRate, short bitsPerSample) {
        this.fileLength = fileLength + (44 - 8);
        dataHdrLeth = fileLength;
        this.channels = channels;
        this.sampleRate = sampleRate;
        this.bitsPerSample = bitsPerSample;
        blockAlign = (short) (channels * bitsPerSample / 8);
        avgBytesPerSec = blockAlign * sampleRate;
    }

    public static void main(String[] args) throws IOException {
//            使用方法：

        // fileLength 录音数据的长度
        WaveHeader8K8bitPcm header = new WaveHeader8K8bitPcm(1024, (short) 6, (short) 8);
        // 返回44个字节的数组
        byte[] waveHeaderBytes = header.getHeader();
        System.out.println(waveHeaderBytes);
    }

    /**
     * @return byte[] 44个字节
     * @throws IOException
     */
    public byte[] getHeader() throws IOException {
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        WriteChar(bos, fileID);//0-3# 以 大端模式 存储内容为"RIFF"的ASCII码(0x52494646)
        WriteInt(bos, fileLength);//4-7# 存储整个文件的字节数(不包含 fileID 和 fileLength 这8个字节)
        WriteChar(bos, wavTag);//8-11# 以 大端模式 存储内容为"WAVE"的ASCII码(0x57415645)
        WriteChar(bos, fmtHdrID);//12-15#以 大端模式 存储内容为"fmt "的ASCII码(0x666d7420)
        WriteInt(bos, fmtHdrLeth);//16-19# 存储子块"fmt "的字节数(不包含 fmtHdrID 和 fmtHdrLeth 这8个字节)
        WriteShort(bos, formatTag);//20-21#	编码格式: 1 PCM ; 6 Alaw; 7 Ulaw
        WriteShort(bos, channels);//22-23#	声道数: 1 Mono; 2 Stereo
        WriteInt(bos, sampleRate);//24-27# 采样率(每秒的样本采集次数): 8K , 16K , 44.1K
        WriteInt(bos, avgBytesPerSec);//28-31# 数据传输速率: 采样率×每次采样大小 (单位是 字节 )
        WriteShort(bos, blockAlign);//32-33# 字节对齐最小单位,即每次采样大小=采样精度×声道数÷8 (单位是 字节 )
        WriteShort(bos, bitsPerSample);//34-35# 采样精度: 一次采样包含的bit位个数
        WriteChar(bos, dataHdrID);//36-39# 以 大端模式 存储内容为"data"的ASCII码(0x64617461)
        WriteInt(bos, dataHdrLeth);//40-43# 存储子块"data"的字节数(不包含Subchunk2ID和Subchunk2Size这8个字节)
        bos.flush();
        byte[] r = bos.toByteArray();
        bos.close();
        return r;
    }

    private void WriteShort(ByteArrayOutputStream bos, int s)
            throws IOException {
        byte[] mybyte = new byte[2];
        mybyte[1] = (byte) ((s << 16) >> 24);
        mybyte[0] = (byte) ((s << 24) >> 24);
        bos.write(mybyte);
    }

    private void WriteInt(ByteArrayOutputStream bos, int n) throws IOException {
        byte[] buf = new byte[4];
        buf[3] = (byte) (n >> 24);
        buf[2] = (byte) ((n << 8) >> 24);
        buf[1] = (byte) ((n << 16) >> 24);
        buf[0] = (byte) ((n << 24) >> 24);
        bos.write(buf);
    }

    private void WriteChar(ByteArrayOutputStream bos, char[] id) {
        for (int i = 0; i < id.length; i++) {
            char c = id[i];
            bos.write(c);
        }
    }

}